﻿#ifndef CMODBUSCLIENT_H
#define CMODBUSCLIENT_H

#include <QObject>
#include <QModbusTcpClient>
#include <QModbusReply>
#include <QThread>
#include <QHash>

class CModbusClient : public QThread
{
    Q_OBJECT
public:
    explicit CModbusClient(QObject *parent = nullptr);
    ~CModbusClient();

signals:
    void signalConnectDevice();
    void signalReadRegisterData(int, int, int);
    void signalWriteRegisterData(int, uint16_t, int);
    void signalWrite16RegisterData(int nStartAddress, QVector<uint16_t> &uValue, int lens, int  type);
    void signalWriteFloatData(int nStartAddress, QVector<float> &uValue, int lens, int  type);
    void signalWrite32RegisterData(int nStartAddress, QVector<uint32_t> &uValue, int lens, int  type);
    void signalUpdateDevice();//one cycle of reading is finished
    void signalUpdateState(bool state);

private slots:
    void slotErrorOccurred(QModbusDevice::Error error);
    void slotStateChanged(QModbusDevice::State state);
    void slotConnectDevice();
    void slotReadyRead();
    void slotReadRegisterData(int nStartAddress, int nNum, int type = QModbusDataUnit::HoldingRegisters);
    void slotWriteRegisterData(int nStartAddress, uint16_t uValue, int type = QModbusDataUnit::HoldingRegisters);
    void slotWrite16RegisterData(int nStartAddress, QVector<uint16_t> &uValue, int lens, int type = QModbusDataUnit::HoldingRegisters);
    void slotWrite32RegisterData(int nStartAddress, QVector<uint32_t> &uValue, int lens, int type = QModbusDataUnit::HoldingRegisters);
    void slotWriteFloatData(int nStartAddress, QVector<float> &uValue, int lens, int type = QModbusDataUnit::HoldingRegisters);

public:
    bool connect(QString strIp, int nPort);
    bool isConnected();
    void release();

    bool getBit(uint16_t uAddr, uint16_t uBit);
    bool readRegister16(uint16_t uAddr, uint16_t &uValue);
    bool readRegister32(uint32_t uAddr, uint32_t &uValue);
    bool readFloat32(uint32_t uAddr, float &uValue);
    bool readCoil(uint16_t uAddr, uint16_t &uValue);

    bool setBit(uint16_t uAddr, uint16_t uBit, bool bState);
    bool writeRegister16(uint16_t uAddr, uint16_t uValue);
    bool writeRegister32(uint32_t uAddr, uint32_t uValue);
    bool writeCoil(uint16_t uAddr, uint16_t uValue);

    bool writeRegister16Vector(uint16_t uAddr, QVector<uint16_t> &uValue, int lens);
    bool writeRegister32Vector(uint32_t uAddr, QVector<uint32_t> &uValue, int lens);
    bool writeRegisterFloatVector(uint32_t uAddr, QVector<float> &uValue, int lens);
    bool writeCoilVector(uint16_t uAddr, QVector<uint16_t> &uValue, int lens);

    bool initReadRegister16(uint32_t uAddr, uint32_t lens);
    bool initReadCoil(uint32_t uAddr, uint32_t lens);

    void emitReadCoil(uint16_t uAddr, int lens);
    void emitReadHoldRegisters(uint16_t uAddr, int lens);

    void printReadHoldRegisters(int &a1,int &a2);
    void disconnect();
protected:
    void run() override;

public:
    //通信统计
    uint32_t  m_connectionSuccessfulTimes;
    uint32_t  m_readTimes;
    uint32_t  m_readSuccessfulTimes;
    uint32_t  m_writeTimes;
    uint32_t  m_writeSuccessfulTimes;
    uint32_t  m_objectType;//0:robotics,1:614

private:
    QModbusTcpClient *m_pClient;
    // 连接状态
    bool m_bConnected;

    // 程序退出，用来退出线程
    bool m_bAppClose;

    // 寄存器
    QHash<uint16_t, uint16_t> m_readValueHoldingRegistersHash;
    QHash<uint16_t, uint16_t> m_readAddrHoldingRegistersHash;
    QHash<uint16_t, uint16_t> m_readResponseAddrHoldingRegistersCoils;

    // 线圈
    QHash<uint16_t, uint16_t> m_readValueCoilsHash;
    QHash<uint16_t, uint16_t> m_readAddrCoilsHash;

};

#endif // CMODBUSCLIENT_H
